package com.mydb.xml;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import com.mydb.MyDbException;
import com.mydb.json.JsonHandler;
import com.mydb.util.PropertiesUtil;

public class XMLBuilder {

	public static XMLBuilder xmlBuilder;
	private String rootPath = "";
	
	private XMLBuilder() {
		PropertiesUtil pu = new PropertiesUtil();
		rootPath = pu.getProperty("database.path");
	}
	
	public static XMLBuilder getInstance() {
		if(xmlBuilder == null){
			xmlBuilder = new XMLBuilder();
		}
		return xmlBuilder;
	}
	
	public Document createRootElement(String xmlName) {
		Document document = DocumentHelper.createDocument();
		Element root = document.addElement(xmlName);

		wirteFile(xmlName, document);
		return document;
	}
	
	public Document getRootElement(String xmlName){
		SAXReader reader = new SAXReader();
		Document document = null;
		try {
			document = reader.read(new File(rootPath + File.separator + xmlName +".xml"));
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return document;
	}
	
	public Element getElement(Document doc, String attrValue) {
		Element element = null;
		Element root = doc.getRootElement();
		List<Node> list = root.selectNodes("//" + root.getName() + "/table[@name=\"" + attrValue + "\"]");
		if(list != null && list.size() > 0) {
			element = (Element)list.get(0);
		}
		return element;
	}
	
	public boolean addElement(String xmlName, String attrValue, Map data) throws MyDbException {
		boolean result = false;
		Document doc = getRootElement(xmlName);
		if(doc == null) {
			throw new MyDbException("database [" + xmlName + "] not exist!");
		}
		
		Element root = doc.getRootElement();
		
		Element element = getElement(doc, attrValue);
		
		if(element == null){
			element = root.addElement("table");
			element.addAttribute("name", attrValue);
		}
		Element dataElement = element.addElement("data");
		JsonHandler jsonHandler = JsonHandler.getInstance();
		dataElement.addText(jsonHandler.format(data));

		wirteFile(xmlName, doc);
		return result;
	}
	
	public int removeElement(String xmlName, String elementName, Map condMap) throws MyDbException {
		Document doc = getRootElement(xmlName);
		Element element = getElement(doc, elementName);
		List<Element> list = element.elements("data");
		JsonHandler jsonHandler = JsonHandler.getInstance();
		int ret = 0;
		for(Element temp : list) {
			if(jsonHandler.containsKey(temp.getText(), condMap)) {
				element.remove(temp);
				ret++;
			}
		}
		wirteFile(xmlName, doc);
		return ret;
	}
	
	public int updateElement(String xmlName, String elementName, Map updateMap, Map condMap) throws MyDbException {
		Document doc = getRootElement(xmlName);
		Element element = getElement(doc, elementName);
		List<Element> list = element.elements("data");
		JsonHandler jsonHandler = JsonHandler.getInstance();
		int ret = 0;
		for(Element temp : list) {
			if(jsonHandler.containsKey(temp.getText(), condMap)) {
				String result = jsonHandler.setJsonData(temp.getText(), updateMap);
				temp.setText(result);
				ret++;
			}
		}
		wirteFile(xmlName, doc);
		return ret;
	}
	
	public List<Map> getElementList(String xmlName, String elementName, Map condMap) throws MyDbException {
		List resultList = new ArrayList();
		Document doc = getRootElement(xmlName);
		Element element = getElement(doc, elementName);
		List<Element> list = element.elements("data");
		JsonHandler jsonHandler = JsonHandler.getInstance();
		if(condMap == null || condMap.isEmpty()) {
			for(Element temp : list) {
				resultList.add(jsonHandler.getDataFromJson(temp.getText()));
			}
		} else {
			for(Element temp : list) {
				if(jsonHandler.containsKey(temp.getText(), condMap)) {
					resultList.add(jsonHandler.getDataFromJson(temp.getText()));
				}
			}
		}
		return resultList;
	}
	
	public void wirteFile(String fileName, Document document) {
		 OutputFormat format = OutputFormat.createPrettyPrint();
		 format.setEncoding("UTF-8"); 
		 XMLWriter writer = null;
		 try {
			writer = new XMLWriter(new FileWriter(rootPath + File.separator + fileName + ".xml"),format);
			writer.write(document);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(writer != null) {
					writer.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void wirteFile(String fileName, Element element) {
		 OutputFormat format = OutputFormat.createPrettyPrint();
		 format.setEncoding("UTF-8"); 
		 XMLWriter writer = null;
		 try {
			writer = new XMLWriter(new FileWriter(rootPath + File.separator + fileName + ".xml",true),format);
			writer.write(element);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(writer != null) {
					writer.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		Map map = new HashMap();
		map.put("id", "1");
		map.put("name", "ok");
		
		XMLBuilder xb = XMLBuilder.getInstance();
	
		try {
			xb.addElement("testdb","user123", map);
		} catch (MyDbException e) {
			e.printStackTrace();
		}
	}

}
